﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace DCT.CodeBox.Log4netWrapper.Codes
{
    /// <summary>
    /// 计时日志
    /// </summary>
    public class DurationLogger : IDisposable
    {
        private Stopwatch watch = null;
        private string name = "";
        private Action<DurationLoggerContext> logAction = null;

        private DurationLogger(string name, Action<DurationLoggerContext> logAction)
        {
            this.watch = new Stopwatch();
            this.name = name;
            this.logAction = logAction;
        }

        /// <summary>
        /// 计时开始
        /// </summary>
        public TimeSpan Start()
        {
            return this.Start("");
        }

        /// <summary>
        /// 计时开始
        /// </summary>
        /// <param name="log">日志内容</param>
        public TimeSpan Start(string log)
        {
            TimeSpan snap = GetTimerSnap();
            this.watch.Start();
            this.logAction(new DurationLoggerContext(snap, name, DurationLoggerStatus.Start, log));
            return snap;
        }

        /// <summary>
        /// 计时重新开始
        /// </summary>
        public TimeSpan Restart()
        {
            return this.Restart("");
        }

        /// <summary>
        /// 计时重新开始
        /// </summary>
        /// <param name="log">日志内容</param>
        public TimeSpan Restart(string log)
        {
            TimeSpan snap = GetTimerSnap();
            this.watch.Restart();
            this.logAction(new DurationLoggerContext(snap, name, DurationLoggerStatus.Restart, log));
            return snap;
        }

        /// <summary>
        /// 计时停止
        /// </summary>
        public TimeSpan Stop()
        {
            return this.Stop("");
        }

        /// <summary>
        /// 计时停止
        /// </summary>
        /// <param name="log">日志内容</param>
        public TimeSpan Stop(string log)
        {
            TimeSpan snap = GetTimerSnap();
            this.watch.Stop();
            this.logAction(new DurationLoggerContext(snap, name, DurationLoggerStatus.Stop, log));
            return snap;
        }

        /// <summary>
        /// 获取当前计时
        /// </summary>
        /// <returns></returns>
        public TimeSpan GetTimerSnap()
        {
            return this.watch.Elapsed;
        }

        /// <summary>
        /// 查看时间是否在运行
        /// </summary>
        public bool IsTimerRunning
        {
            get
            {
                return this.watch.IsRunning;
            }
        }

        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="log"></param>
        public TimeSpan Log(string log)
        {
            TimeSpan snap = GetTimerSnap();
            this.logAction(new DurationLoggerContext(snap, name, DurationLoggerStatus.RunningLog, log));
            return snap;
        }

        /// <summary>
        /// 销毁
        /// </summary>
        public void Dispose()
        {
            this.watch = null;
            logAction = null;
        }

        /// <summary>
        /// 设置默认日志
        /// </summary>
        public static Action<DurationLoggerContext> DefaultLogAction
        {
            get;
            set;
        }

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <param name="name"></param>
        /// <param name="logAction"></param>
        /// <returns></returns>
        public static DurationLogger Create(string name, Action<DurationLoggerContext> logAction)
        {
            if (logAction == null)
            {
                throw new NullReferenceException("logAction is null");
            }
            return new DurationLogger(name, logAction);
        }

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static DurationLogger Create(string name)
        {
            if (DefaultLogAction == null)
            {
                throw new NullReferenceException("DefaultLogAction is null");
            }
            return Create(name, DefaultLogAction);
        }
    }

    /// <summary>
    /// 计时Log状态
    /// </summary>
    public enum DurationLoggerStatus
    {
        /// <summary>
        /// 启动
        /// </summary>
        Start,
        /// <summary>
        /// 停止
        /// </summary>
        Stop,
        /// <summary>
        /// 重新开始
        /// </summary>
        Restart,
        /// <summary>
        /// 计时日志
        /// </summary>
        RunningLog
    }

    /// <summary>
    /// 计时日志上下文
    /// </summary>
    /// <remarks>为了效率，使用struct</remarks>
    public struct DurationLoggerContext
    {
        private TimeSpan elasped;
        private string name;
        private DurationLoggerStatus status;
        private string log;

        /// <summary>
        /// 当前计时时间
        /// </summary>
        public TimeSpan Elasped { get { return elasped; } }
        /// <summary>
        /// 日志标识
        /// </summary>
        public string Name { get { return name; } }
        /// <summary>
        /// 当前状态
        /// </summary>
        public DurationLoggerStatus Status { get { return this.status; } }
        /// <summary>
        /// 日志内容
        /// </summary>
        public string Log { get { return this.log; } }

        public DurationLoggerContext(TimeSpan ts, string name, DurationLoggerStatus status, string log)
        {
            this.elasped = ts;
            this.name = name;
            this.status = status;
            this.log = log ?? "";
        }
    }
}
